前幾天完成基礎消費查詢後,SubWise 已經能夠回答「我最近有哪些消費?」或「我這個月花了多少錢?」。但在實際測試與日常使用中,很快發現一個關鍵盲點:使用者想查的通常不只是「全部消費」,而是特定情境的支出。
例如日常中更常見的問法是:「我這個月交通花多少?」、「最近 Food 花了多少錢?」。如果每次查詢都只能將整段期間的資料全部倒出來,查詢體驗依然不夠直覺。因此今天的開發核心,是讓 SubWise 的查詢能力從單純的「查詢某個期間」,進一步升級為 「查詢某個期間 + 指定消費分類」 。
在目前的 Agent 架構下,Gemini 專注負責將自然語言轉譯為結構化 JSON,真正的資料過濾與計算則交由後端 Python 處理:
使用者輸入自然語言
↓
Gemini
↓
Query JSON (新增 category 欄位)
↓
query_service.py
↓
Google Sheets
↓
整理並計算查詢結果
↓
LINE 回覆
當使用者詢問「我這個月交通花多少?」,Gemini 會解析出帶有 category 條件的 Query 物件:
{
"type": "query",
"target": "expense",
"period": "month",
"keyword": null,
"category": "Transport"
}
目前系統支援的標準分類包含:Food、Transport、Entertainment、Shopping、Bills、Health、Education、Subscription、Other。這種分工讓 AI 專注於意圖識別,後端專注於資料處理,維持系統的高內聚與低耦合。
在資料服務層新增 filter_expenses_by_category(records, category=None),確保函式職責單一且可組合:
def filter_expenses_by_category(records, category=None):
"""
根據消費分類篩選資料。
"""
if not category:
return records
filtered = []
for record in records:
record_category = str(record.get("Category", "")).strip()
if record_category == category:
filtered.append(record)
return filtered
若使用者未指定分類,則回傳全量紀錄;若指定分類(如 Transport),則僅保留符合該類別的資料列。
將分類篩選無縫接入既有的 query_data() 處理流程中,實現「先縮小資料範圍,再進行統計與排序」的設計原則:
Google Sheets 原始紀錄
↓
期間篩選 (filter_expenses)
↓
分類篩選 (filter_expenses_by_category) ← 今天新增
↓
統計總額與筆數
↓
計算最高單筆與日期排序
↓
格式化輸出 (format_expense_result)
核心程式碼片段如下:
records = get_expenses()
records = filter_expenses(records, period)
records = filter_expenses_by_category(records, category)
return format_expense_result(records, period)
這樣的流程確保了當使用者詢問「這個月交通花多少?」時,系統是針對「本月 + Transport」的子集合精準計算,而非撈出全月資料後再進行二次拼湊。
為了讓輸出更具產品感,除了總支出與消費筆數,還額外加入了最高單筆消費與按時間倒序的最近消費清單。同時建立分類顯示名稱對照表,將內部英文標籤轉換為帶有 Emoji 的繁體中文:
CATEGORY_DISPLAY_NAMES = {
"Food": "🍜 餐飲",
"Transport": "🚇 交通",
"Entertainment": "🎮 娛樂",
"Shopping": "🛍️ 購物",
"Bills": "💡 生活帳單",
"Health": "❤️ 醫療保健",
"Education": "📚 學習",
"Subscription": "🔔 訂閱",
"Other": "📦 其他"
}
內部邏輯維持標準字串以利運算,對外呈現則轉化為友善介面,讓最終回覆在 LINE 上呈現清晰易讀的版面:
💰 SubWise 消費查詢
📅 查詢期間:month
💵 總支出:NT$350
🧾 消費筆數:5 筆
🔥 最高單筆消費
📅 日期:2026-08-20
💵 金額:NT$100
📂 分類:🚇 交通
📝 備註:禾誕股份有限公司
📋 最近消費:
• 2026-08-21|🚇 交通|NT$100|捷運
• 2026-08-20|🚇 交通|NT$100|禾誕股份有限公司
• 2026-08-17|🚇 交通|NT$50|捷運
• 2026-08-10|🚇 交通|NT$50|捷運
• 2026-08-08|🚇 交通|NT$50|MRT
先針對 filter_expenses_by_category() 進行單元測試,驗證以 Food 與 Transport 篩選測試陣列時皆能精確過濾無誤。
接著透過 process_ai_message() 執行端到端自然語言整合測試:
測試「我這個月交通花多少錢?」:Gemini 正確產出 period: month 與 category: Transport,並成功回傳總支出 NT$350(5 筆)及對應明細。
測試「我最近 Food 花多少錢?」:成功解析為本週餐飲查詢,輸出「🍜 餐飲」之總支出 NT$550(4 筆)。
category 篩選欄位filter_expenses_by_category() 分類過濾函式query_data() 流程,實現「期間 + 分類」雙重條件查詢CATEGORY_DISPLAY_NAMES 對照表,提升 LINE 輸出體驗目前 SubWise 的自然語言查詢維度涵蓋:
| 查詢維度 | 範例問法 | 轉譯條件 |
|---|---|---|
| 📅 期間查詢 | 「我這個月花多少?」 | period: month |
| 📅 近期動態 | 「我最近有哪些消費?」 | period: week |
| 🏷️ 期間 + 分類 | 「我這個月交通花多少?」 | period: month, category: Transport |
| 🏷️ 近期 + 分類 | 「最近 Food 花多少?」 | period: week, category: Food |
| 📊 統計輸出 | 總額、筆數、最高單筆、按日排序明細 | 完整格式化輸出 |
在消費查詢與分析逐步完善後,Day 24 將正式跨入核心場景之一的 「訂閱管理」 ——實作週期性訂閱項目的自然語言新增與 Google Sheets 寫入,讓 SubWise 也能妥善追蹤每月的固定扣款支出。我們明天見!